package com.zhuhjay.common.swagger.config;

import com.github.xiaoymin.knife4j.spring.configuration.Knife4jInfoProperties;
import com.zhuhjay.common.base.constant.SecurityConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.ApiResourceController;

import java.util.Collections;
import java.util.List;

/**
 * <b>q: @Indexed注解使用后导致 {@link ApiResourceController} 无法访问</b>
 * <p>
 * 1. 问题原因: @Indexed注解会导致swagger-springmvc的ApiListingResourceScanner类中的apiListingCache属性无法注入
 * </p>
 * <p>
 * 2. 解决方案:
 * </p>
 * <pre>
 *       1. 不使用@Indexed注解
 *       2. 使用spring.factories文件配置
 *       3. 使用spring-boot-starter-actuator的/beans接口查看bean是否注入成功
 * </pre>
 *
 * <p>登录脚本AfterScript</p>
 * <pre>
 * ```javascript
 * let code = ke.response.data.code;
 * if(code === 200){
 *     // 获取token(需要根据实际的请求头参数来获取)
 *     let token = ke.response.headers['authorization-genericboot'].split(" ")[1];
 *     ke.global.setAllHeader("Authorization-GenericBoot", `Basic ${token}`);
 * }
 * ```</pre>
 *
 * @author ZhuHJay
 * @date 2023/2/24 23:09
 */
@Slf4j
@Configuration
/* 对JSR303提供支持 */
@Import(BeanValidatorPluginsConfiguration.class)
public class Knife4jConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo(knife4jInfoProperties()))
                .securityContexts(securityContexts())
                .securitySchemes(securitySchemes())
                .select()
                // 配置扫描接口
                .apis(RequestHandlerSelectors.basePackage("com.zhuhjay.app.web.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    @Bean
    public Knife4jInfoProperties knife4jInfoProperties() {
        return new Knife4jInfoProperties();
    }

    private ApiInfo apiInfo(Knife4jInfoProperties properties) {
        return new ApiInfoBuilder()
                .title(properties.getTitle())
                .description(properties.getDescription())
                .version(properties.getVersion())
                .contact(new Contact(properties.getConcat(), properties.getUrl(), properties.getEmail()))
                .build();
    }

    private List<SecurityContext> securityContexts() {
        return Collections.singletonList(
                SecurityContext.builder()
                    .securityReferences(
                        Collections.singletonList(
                            new SecurityReference(
                                "JWT_TOKEN",
                                new AuthorizationScope[]{
                                        new AuthorizationScope("global", "TOKEN")
                                })
                        )
                    )
                    .forPaths(PathSelectors.none())
                    .build()
        );
    }

    private List<SecurityScheme> securitySchemes() {
        return Collections.singletonList(new ApiKey("JWT_TOKEN", SecurityConstant.AUTH_HEADER_KEY, "header"));
    }

}
